package handler

import (
	"context"
	"fmt"
	"gitee.com/worklz/dtm-tcc-demo/server-inventory/domain/dto"
	inventorypb "gitee.com/worklz/dtm-tcc-demo/server-inventory/proto/inventory"
	"sync"
)

type InventoryHandler struct {
	inventorypb.UnimplementedInventoryServiceServer                           // 关键：嵌入默认实现
	inventory                                       map[string]*dto.Inventory // 库存存储
	txStatus                                        map[string]string         // 事务状态记录 tx_id -> status
	mu                                              sync.RWMutex
}

var _ inventorypb.InventoryServiceServer = (*InventoryHandler)(nil)

func NewInventoryHandler() *InventoryHandler {
	return &InventoryHandler{
		inventory: make(map[string]*dto.Inventory),
		txStatus:  make(map[string]string),
	}
}

// 初始化产品库存（实际项目中应该从数据库加载）
func (h *InventoryHandler) initProduct(productId string) {
	if _, exists := h.inventory[productId]; !exists {
		h.inventory[productId] = &dto.Inventory{
			ProductID: productId,
			Available: 1000, // 默认初始库存
			Frozen:    0,
		}
	}
}

// TryDeductInventory 尝试扣减库存-Try阶段
func (h *InventoryHandler) TryDeductInventory(ctx context.Context, req *inventorypb.TccDeductInventoryRequest) (res *inventorypb.TccDeductInventoryResponse, err error) {
	h.mu.Lock()
	defer h.mu.Unlock()
	//err = status.Errorf(500, "测试未知库存扣减异常1")
	//res = &inventorypb.TccDeductInventoryResponse{
	//	Success: false,
	//	Message: "测试未知库存扣减异常2",
	//}
	return

	// 幂等性检查
	if status, exists := h.txStatus[req.TxId]; exists {
		if status == "try" {
			res = &inventorypb.TccDeductInventoryResponse{Success: true}
			return
		}
		res = &inventorypb.TccDeductInventoryResponse{
			Success: false,
			Message: fmt.Sprintf("事务状态错误: %s", status),
		}
		return
	}

	// 初始化产品库存
	h.initProduct(req.ProductId)

	// 检查库存是否充足
	inv := h.inventory[req.ProductId]
	if inv.Available < req.Quantity {
		res = &inventorypb.TccDeductInventoryResponse{
			Success: false,
			Message: "库存不足",
		}
		return
	}

	// 扣减可用库存，增加冻结库存
	inv.Available -= req.Quantity
	inv.Frozen += req.Quantity
	h.inventory[req.ProductId] = inv
	h.txStatus[req.TxId] = "try"

	res = &inventorypb.TccDeductInventoryResponse{Success: true}
	return
}

// ConfirmDeductInventory 确认扣减库存-Confirm阶段
func (h *InventoryHandler) ConfirmDeductInventory(ctx context.Context, req *inventorypb.TccDeductInventoryRequest) (res *inventorypb.TccDeductInventoryResponse, err error) {
	h.mu.Lock()
	defer h.mu.Unlock()

	// 幂等性检查
	if status, exists := h.txStatus[req.TxId]; exists {
		if status == "confirm" {
			res = &inventorypb.TccDeductInventoryResponse{Success: true}
			return
		}
		if status != "try" {
			res = &inventorypb.TccDeductInventoryResponse{
				Success: false,
				Message: fmt.Sprintf("事务状态错误: %s", status),
			}
			return
		}
	} else {
		// 空回滚处理
		res = &inventorypb.TccDeductInventoryResponse{Success: true}
		return
	}

	// 扣减冻结库存（完成实际扣减）
	inv, exists := h.inventory[req.ProductId]
	if !exists {
		res = &inventorypb.TccDeductInventoryResponse{
			Success: false,
			Message: "产品不存在",
		}
		return
	}

	inv.Frozen -= req.Quantity
	h.inventory[req.ProductId] = inv
	h.txStatus[req.TxId] = "confirm"

	res = &inventorypb.TccDeductInventoryResponse{Success: true}
	return
}

// CancelDeductInventory 取消扣减库存-Cancel阶段
func (h *InventoryHandler) CancelDeductInventory(ctx context.Context, req *inventorypb.TccDeductInventoryRequest) (res *inventorypb.TccDeductInventoryResponse, err error) {
	h.mu.Lock()
	defer h.mu.Unlock()

	// 幂等性检查
	if status, exists := h.txStatus[req.TxId]; exists {
		if status == "cancel" {
			res = &inventorypb.TccDeductInventoryResponse{Success: true}
			return
		}
		if status != "try" {
			res = &inventorypb.TccDeductInventoryResponse{
				Success: false,
				Message: fmt.Sprintf("事务状态错误: %s", status),
			}
			return
		}
	} else {
		// 空回滚处理
		res = &inventorypb.TccDeductInventoryResponse{Success: true}
		return
	}

	// 解冻库存，恢复可用库存
	inv, exists := h.inventory[req.ProductId]
	if !exists {
		res = &inventorypb.TccDeductInventoryResponse{
			Success: false,
			Message: "产品不存在",
		}
		return
	}

	inv.Frozen -= req.Quantity
	inv.Available += req.Quantity
	h.inventory[req.ProductId] = inv
	h.txStatus[req.TxId] = "cancel"

	res = &inventorypb.TccDeductInventoryResponse{Success: true}
	return
}
